home *** CD-ROM | disk | FTP | other *** search
/ Apple WWDC 1996 / WWDC96_1996 (CD).toast / Technology Materials / QuickTime VR / MacOS / QuickDraw™ 3D 1.0.6F4 SDK / Samples / SampleCode / Tumbler and Podium / Tumbler_drag.c < prev    next >
Encoding:
Text File  |  1995-11-13  |  24.4 KB  |  820 lines  |  [TEXT/MPS ]

  1. // Tumbler_drag.c
  2. //
  3. // Dragging routines. The code in this file implements the geometry
  4. // dragging features of this program.  The last function in this file,
  5. // DoDragObjects is called when a mouseDown is detected in the hilite region
  6. // of the current object.
  7. //  
  8. // Here's some background from Nick for debugging this mess.  First off the drag manager 
  9. // is not a simple animal.
  10. //
  11. // High-level or source-level debuggers won't work with Drag Manager callback routines.  
  12. // That's because of the way the Drag Manager performs process switching.  The only 
  13. // high-level debugger that does work with the Drag Manager is VoodooMonkey, an "experimental 
  14. // prototype" debugger you can find on the November Developer CD.  Note that VoodooMonkey 
  15. // is unsupported by Apple.  The other more-supportable option is to use MacsBug (or your 
  16. // favorite low-level debugger) for real-time debugging.  But since this 3d stuff will only
  17. // work on power macintosh cpu's (unless you have the souce code, which developers don't :0>)
  18. // MacsBug won't help you much.  And I was using a version of CodeWarrior that didn't seem to 
  19. // want to put any symbols in, which means Macsbug is not really an option (debugging what
  20. // MB thinks is the 68k equivalent of the actual PPC instructions, with no symbols, ain't
  21. // my idea of fun.  And don't think DebugStr will help you any - if you are running with 
  22. // the MetroWerks (MW) high level debugger, your mAchine will crash big time.  MW debugger
  23. // wants to display the debugstr in a nice little dialog, which means it has to do a context
  24. // switch.  Why is this bad... read on McDuff:
  25. //
  26. // The Drag Manager is actually making full context switches for each process that has  
  27. // tracking/receive handlers as an object is dragged over a valid drag region.  While this 
  28. // may sound a bit drastic or scary, it isn't really that bad because a drag is a modal operation,  
  29. // and as long as the user is dragging an object, the System (namely the Drag Manager) is in  
  30. // control to call tracking and receive handlers as appropriate.  So when your receive handler  
  31. // is called and all events pending for your process have been handled, your application is  
  32. // eliglble for a context switch the next time WaitNextEvent is called.  And when WNE is called  
  33. // and a context switch occurs, the Drag Manager has lost track over what process is currently  
  34. // the context.  This is also why you cannot use source-level debuggers to debug drag handlers,  
  35. // because context switches are controlled by those debuggers, and once you're in a Drag you  
  36. // cannot change the Process Manager state.
  37. //  
  38. // In case you're interested, one technique that works well for receive handlers is to send an  
  39. // Apple event to yourself with the relevant information about the drag, and process it at  
  40. // WaitNextEvent time.  Sending an Apple event to yourself can be done even if you're not the  
  41. // frontmost application, and it allows you to process the Drag at WaitNextEvent time, meaning  
  42. // you can call your Alert routine and change process states without any problems.  Another  
  43. // benefit to this approach is that you'll be able to use source level debuggers to work on  
  44. // your receive handlers.
  45. //
  46. // The only thing to beware of if you do this (and this is what do here) is to get the PSN 
  47. // directly - AppleEvents.h gives a constant (kCurrentProcess) that you can stick in the low
  48. // longword of the PSN that will cause the event to essentially be dispatched as a function
  49. // call, and that is not what we want here.  By getting the process serial number (PSN) of
  50. // our own process and using that in the AppleEvent we ensure that the event is dispatched 
  51. // to our process so we can deal with it in the main event loop, rather than being mapped into
  52. // and unwanted funtion call (which since we would still be in the drag managers context would
  53. // prevent us from being able to debug using anything reasonable).  Check out Tumbler_AEVT for
  54. // more details on this.
  55. //
  56. // Nitin Gantatra whined so much that I'd stolen the comments above, that I feel compelled to 
  57. // add:
  58. //
  59. //    Author of lame gratuitous drag manager comments: Jim Luther
  60. //
  61. //    Author:        Nick Thompson, based on the original by
  62. //                Pablo Fernicola, based on Rob Johnson's drag text sample,
  63. //                with extensive stealing from grobbins SimpleDrag sample.
  64. //
  65. //    Modification history:
  66. //
  67. //    11/26/94    nick    removed dead code, tightened up the drag code, based on
  68. //                        grobbins' excellent simpledrag sample
  69. //    11/25/94    nick    added events for dragging, this lets us do
  70. //                        source level debugging of the drag receiver, see Tumbler_aevt.
  71. //
  72. //    Copyright © 1992-95 Apple Computer, Inc., All Rights Reserved
  73. //
  74. // to do: store the document reference as a handle in the window's refcon
  75. //
  76.  
  77.  
  78. #define NAGELS_DEMO        // pre-allocate handles
  79.  
  80.  
  81. #include <QDOffscreen.h>
  82. #include <Folders.h>
  83. #include <Drag.h>
  84. #include <SegLoad.h>
  85. #include <Types.h>
  86.  
  87. #include "Tumbler_globals.h"
  88.  
  89. #include "QD3D.h"
  90. #include "QD3DGroup.h"
  91. #include "QD3DStorage.h"
  92. #include "QD3DIO.h"
  93. #include "QD3DView.h"
  94. #include "QD3DDrawContext.h"
  95. #include "QD3DPick.h"
  96. #include "QD3DShader.h"
  97. #include "QD3DTransform.h"
  98. #include "QD3DGroup.h"
  99.  
  100. #include "Tumbler_prototypes.h"
  101. #include "Tumbler_file.h"
  102. #include "Tumbler_resources.h"
  103. #include "Tumbler_offscreen.h"
  104.  
  105.  
  106. #include "Tumbler_AEVT.h"            // grab our apleEvent handlers and data structures
  107.                                     // used for debugging
  108. #include "Tumbler_drag.h"
  109.  
  110.  
  111.  
  112. //    Can use custom drawing procedure. Just uncomment out this line:
  113. //    #define USE_CUSTOM_DRAWING
  114.  
  115.  
  116. // global data for my Drag Manager handlers
  117.  
  118. typedef struct DragHandlerGlobals 
  119. {
  120.     Boolean         acceptableDragFlag;
  121.     Boolean         windowIsHilightedFlag;
  122. } ;
  123.  
  124. typedef struct DragHandlerGlobals
  125.     DragHandlerGlobals, *DragHandlerGlobalsPtr;
  126.  
  127. static DragHandlerGlobals pDragHandlerGlobals;
  128.  
  129.  
  130. //-----------------------------------------------------------------------
  131. //    MyDrawingProc
  132. //
  133. //    Simple drawing proc for dragging objects. This drawing procedure is very similar to
  134. //    the Drag Manager's built in drawing proc, except that it uses a solid black pattern
  135. //    to draw the region instead of using the dithered gray pattern.
  136. //
  137. // DONT USE THIS ON POWERPC as there is a quickdraw bug that leaves artifacts
  138. // everywhere (talk to Nitin Ganatra for the gory details).
  139.  
  140.  
  141. static
  142. pascal OSErr MyDrawingProc(DragRegionMessage message,
  143.                            RgnHandle showRgn, Point showOrigin,
  144.                            RgnHandle hideRgn, Point hideOrigin,
  145.                            void *dragDrawingRefCon, DragReference theDragRef)
  146.  
  147. {    OSErr            result = paramErr;
  148.     RgnHandle        tempRgn;
  149.  
  150.     switch(message) {
  151.  
  152.         case dragRegionBegin:
  153.  
  154.             //
  155.             //    No initialization necessary for our drawing proc. Make sure noErr
  156.             //    is returned, otherwise the Drag Manager will revert back to it's
  157.             //    built in drawing proc.
  158.             //
  159.  
  160.             result = noErr;
  161.             break;
  162.  
  163.         case dragRegionDraw:
  164.  
  165.             //
  166.             //    Find the difference between the region needed to be shown and the
  167.             //    region needed to be hidden. Inverting the difference removes the pixels
  168.             //    that must be hidden and shows the pixels that must be shown in one step.
  169.             //
  170.  
  171.             XorRgn(showRgn, hideRgn, tempRgn = NewRgn());
  172.             InvertRgn(tempRgn);
  173.             DisposeRgn(tempRgn);
  174.             result = noErr;
  175.             break;
  176.  
  177.         case dragRegionHide:
  178.  
  179.             //
  180.             //    Simply hide the region given to us by inverting it.
  181.             //
  182.  
  183.             InvertRgn(hideRgn);
  184.             result = noErr;
  185.             break;
  186.     }
  187.  
  188.     return(result);
  189. }
  190.  
  191.  
  192.  
  193. //------------------------------------------------------------------------------------
  194. //    MySendDataProc - provides data for the drag when requested.
  195.  
  196. static pascal OSErr MySendDataProc(FlavorType theType, void *refCon,
  197.                             ItemReference theItem, DragReference theDrag)
  198.  
  199. {
  200.     DocumentPtr theDocument = (DocumentPtr ) refCon;
  201.     unsigned long    validSize;
  202.     
  203.     // so what do they want??
  204.     
  205.     if (theType == '3DMF') {
  206.  
  207.         if( theDocument->documentGroup ) {
  208.         
  209.             Handle                theData;
  210.             TQ3StorageObject        storage;
  211.             TQ3FileObject        fd;
  212.             TQ3TransformObject     xform;
  213.             TQ3GroupPosition        position;
  214.             Boolean                didAllocate = false;        // set to true if we did allocate memory
  215.             
  216.             if( Q3Object_IsType(theDocument->documentGroup, kQ3DisplayGroupTypeOrdered)) {
  217.                 Q3Group_GetFirstPositionOfType(theDocument->documentGroup, kQ3ShapeTypeTransform,&position);
  218.             } else {
  219.                 Q3Group_GetFirstPosition(theDocument->documentGroup, &position);
  220.             }
  221.  
  222.             xform = Q3MatrixTransform_New( &theDocument->modelRotation);
  223.             
  224.             position = Q3Group_AddObjectBefore(theDocument->documentGroup, position, xform);
  225.     
  226.             Q3Object_Dispose(xform);
  227.             
  228. #ifdef NAGELS_DEMO
  229.             // HO HO HO.  Actually we *do* need a way to approximate the 
  230.             // size this handle needs to be so we can preflight
  231.                         
  232.             if((theData = NewHandle(1024 * 1024 )) != nil)     {        // ask for 1M
  233.             
  234.                 MoveHHi( theData ) ;
  235.                 HLock( theData ) ;
  236.                 didAllocate = true ;
  237.                 storage = Q3HandleStorage_New( theData, GetHandleSize( theData ) );
  238.                 
  239.             }
  240.             else {
  241.             
  242.                 storage = Q3HandleStorage_New( nil, 0 );
  243.                 
  244.             }
  245. #else
  246.             storage = Q3HandleStorage_New(nil,0);
  247. #endif            
  248.             if (storage == nil)
  249.                 goto bail;
  250.             
  251.             fd = Q3File_New();
  252.             
  253.             if (fd == nil)
  254.                 goto bail;
  255.  
  256.             Q3File_SetStorage(fd, storage);
  257.                         
  258.             Tumbler_WriteScene(fd, 
  259.                                 false,
  260.                                 theDocument) ;
  261.     
  262.             Q3HandleStorage_Get(storage, &theData, &validSize);
  263.             HLock(theData);
  264.             SetDragItemFlavorData(theDrag, theItem, '3DMF', (Ptr) *theData,
  265.                                   validSize, 0L);
  266.             HUnlock(theData);
  267.             Q3Object_Dispose(storage);
  268.             Q3Object_Dispose(fd);
  269.             
  270. #ifdef NAGELS_DEMO
  271.             if( didAllocate == true ) {
  272.                 DisposeHandle(theData);
  273.             }
  274. #endif
  275.  
  276.         } 
  277.         else {
  278.             return(badDragFlavorErr);
  279.         }
  280.     }  
  281.     else {
  282.  
  283.         return(badDragFlavorErr);
  284.  
  285.     }
  286.     return(noErr);
  287.     
  288. bail:
  289.     return(badDragFlavorErr);
  290. }
  291.  
  292.  
  293. //-----------------------------------------------------------------------
  294. // DragItemsAreAcceptable returns true if the contents (data) of
  295. // the drag are acceptable by a window of this application
  296. //
  297. // DragItemsAreAcceptable is called by the tracking and 
  298. // receive handlers
  299. Boolean DragItemsAreAcceptable(DragReference theDrag) ;
  300.  
  301. Boolean DragItemsAreAcceptable(DragReference theDrag)
  302. {
  303.     OSErr            retCode;
  304.     unsigned short    totalItems;
  305.     ItemReference    itemRef;
  306.     Boolean            acceptableFlag;
  307.     HFSFlavor         currHFSFlavor;
  308.     Size            flavorDataSize;
  309.     FlavorFlags        currFlavorFlags;
  310.     
  311.  
  312.     acceptableFlag = false;
  313.  
  314.     // this app can only accept the drag of a single item
  315.     retCode = CountDragItems(theDrag, &totalItems);
  316.     if (retCode == noErr && totalItems == 1) {
  317.     
  318.         // get the reference number of the dragged item
  319.         retCode = GetDragItemReferenceNumber(theDrag, 1, &itemRef);
  320.         if (retCode == noErr) {
  321.             
  322.             // use GetFlavorFlags to check on flavor existence of PICT data
  323.             // without forcing translation
  324.             
  325.             if (GetFlavorFlags (theDrag, itemRef, 'PICT', &currFlavorFlags) == noErr) {
  326.                 acceptableFlag = true;
  327.             }
  328.             else if (GetFlavorFlags (theDrag, itemRef, '3DMF', &currFlavorFlags) == noErr) {
  329.                 acceptableFlag = true;
  330.             }
  331.             else {
  332.             
  333.                 // check if the item is a file spec for a PICT file
  334.                 flavorDataSize = sizeof(HFSFlavor);
  335.                 retCode = GetFlavorData(theDrag, itemRef, flavorTypeHFS, &currHFSFlavor,
  336.                     &flavorDataSize, 0);
  337.                 
  338.                 if (retCode == noErr &&  (currHFSFlavor.fileType == 'PICT' 
  339.                                 || currHFSFlavor.fileType == '3DMF'
  340.                                 || currHFSFlavor.fileType == 'TEXT' )) 
  341.                     acceptableFlag = true;
  342.             }
  343.         }
  344.     }
  345.  
  346.     return acceptableFlag;
  347. }
  348.  
  349.  
  350. //-----------------------------------------------------------------------
  351. // DragIsNotInSourceWindow returns true if the drag in progress
  352. // is not in the same window it originated in
  353. //
  354. // DragIsNotInSourceWindow is called by the tracking and receive handlers
  355. //
  356. // Note that, if this application allowed items to be dragged within
  357. // its windows, this function would not be appropriate.
  358. // Instead, hilighting would probably occur in the source window
  359. // when the dragHasLeftSourceWindow flag is set, and the receive
  360. // handler wouldn't check this at all
  361.  
  362. static
  363. Boolean DragIsNotInSourceWindow(DragReference theDrag)
  364. {
  365.     DragAttributes currDragFlags;
  366.     
  367.     (void) GetDragAttributes(theDrag, &currDragFlags);
  368.     return ((currDragFlags & dragInsideSenderWindow) == 0);
  369. }
  370.  
  371.  
  372. //-----------------------------------------------------------------------
  373. // MouseInContentRgn returns true if the current mouse is in the content
  374. // area of the window (but not necessarily in the visible rgn)
  375.  
  376. static
  377. Boolean MouseIsInContentRgn(DragReference theDrag, WindowPtr theWindow)
  378. {
  379.     Point mousePt;
  380.     
  381.     (void) GetDragMouse(theDrag, &mousePt, nil);
  382.     return PtInRgn(mousePt, ((WindowPeek) theWindow)->contRgn);
  383. }
  384.  
  385. //-----------------------------------------------------------------------
  386. //    MyReceiveDropHandler
  387. //
  388. //    Called by the Drag Manager when a drop occurs over one of the DoDragObjects document windows.
  389.  
  390. pascal OSErr MyReceiveDropHandler(WindowPtr theWindow, unsigned long handlerRefCon,
  391.                                   DragReference theDrag);
  392.  
  393. pascal OSErr MyReceiveDropHandler(WindowPtr theWindow, unsigned long handlerRefCon,
  394.                                   DragReference theDrag)
  395.  
  396. {
  397.     OSErr                result;
  398.     Rect                theRect, srcRect;
  399.     unsigned short        items, index;
  400.     ItemReference        theItem;
  401.     DragAttributes        attributes;
  402.     StScrpHandle        stylHandle;
  403.     Size                dataSize, pictSize;
  404.     short                offset, selStart, selEnd, mouseDownModifiers, mouseUpModifiers, moveText;
  405.     DocumentPtr         theDocument = (DocumentPtr ) handlerRefCon;
  406.     Point                thePoint;
  407.     TQ3Object             objects = nil;
  408.  
  409.     Boolean                dataObtainedFlag;
  410.     OSErr                retCode;
  411.     
  412.     OSType                theDragFlavor ;
  413.     Point                mouseLoc ;
  414.     
  415.     
  416.     dataObtainedFlag = false;
  417.     if (!DragItemsAreAcceptable(theDrag) ||
  418.             !MouseIsInContentRgn(theDrag, theWindow) ||
  419.             !DragIsNotInSourceWindow(theDrag)) 
  420.         return dragNotAcceptedErr;
  421.                 
  422.     // We will only support one item, so get its reference number.
  423.     result = GetDragItemReferenceNumber(theDrag, 1, &theItem);
  424.     if (result != noErr)
  425.         return result;
  426.  
  427.     GetDragAttributes(theDrag, &attributes);
  428.     GetDragModifiers(theDrag, 0L, &mouseDownModifiers, &mouseUpModifiers);
  429.     
  430.     //    Loop through all of the drag items contained in this drag
  431.     
  432.     SetRect(&theRect, 0, 0, 0, 0);
  433.  
  434.     // we ensured above that we only deal with one item being dragged to us...
  435.     
  436. //    CountDragItems(theDrag, &items);
  437.  
  438.     //    Get the item's reference, so we can refer to it.
  439.     GetDragItemReferenceNumber(theDrag, 1, &theItem);
  440.     
  441.     // get the location the user dropped the data
  442.     GetDragMouse(theDrag, &mouseLoc, nil ) ;
  443.  
  444.     //    Try to get the flags for a '3DMF' flavor. If this returns noErr,
  445.     //    then we know that a '3DMF' flavor exists in the item.
  446.  
  447.     result = GetFlavorDataSize(theDrag, theItem, '3DMF', &dataSize);
  448.     if (result == noErr) {
  449.         theDragFlavor = '3DMF' ;
  450.     }
  451.     else if((result = GetFlavorDataSize(theDrag, theItem, 'PICT', &dataSize)) == noErr) {
  452.         theDragFlavor = 'PICT' ;
  453.     } 
  454.     else {
  455.         // Couldn't get 3DMF or PICT data so try to get HFS-flavor data.
  456.         HFSFlavor        theHFSFlavor;
  457.         dataSize = sizeof(HFSFlavor);
  458.         result = GetFlavorData(theDrag, theItem, flavorTypeHFS, 
  459.                                                 &theHFSFlavor, &dataSize, 0);
  460.                                                 
  461.         if(theHFSFlavor.fileType != 'PICT' 
  462.             || theHFSFlavor.fileType != '3DMF'
  463.             || theHFSFlavor.fileType != 'TEXT' ) {
  464.             result = paramErr ;
  465.         }
  466.     }
  467.  
  468.     
  469.     // so we either have nothing or something (in the form of 3DMF or PICT data)
  470.     if (result == noErr) {
  471.         
  472.         // create a new data handle to hold the data the user just dragged in
  473.         // this needs to be the size of the data, plus the size of the 
  474.  
  475.         myPrivateDataHdl        thePrivateData = nil ;
  476.         long                    recordSize ;    
  477.  
  478.  
  479.         recordSize = sizeof( myPrivateDataRec ) ;
  480.         
  481.         // create a handle large enough for the data
  482.         thePrivateData = (myPrivateDataHdl)NewHandle( (long)(dataSize +  recordSize)) ;
  483.         
  484.         if( thePrivateData == nil )
  485.             return MemError() ;
  486.     
  487.         
  488.         (**thePrivateData).myTypeOfData = theDragFlavor ;
  489.         (**thePrivateData).myDocument = theDocument ;        // ideally we should store the doc in the windows refcon, this is hacky ???
  490.         (**thePrivateData).myDataSize = dataSize ;
  491.         (**thePrivateData).myWindow = theWindow ;
  492.         (**thePrivateData).myLocation = mouseLoc ;
  493.  
  494.         // Lock and load, I dunno if GetFlavorData moves memory, I'm just assuming it may...
  495.         
  496.         MoveHHi( (Handle)thePrivateData ) ;
  497.         HLock( (Handle)thePrivateData ) ;
  498.  
  499.         //  passing (**thePrivateData) in dereferenced - ASSUMES the hnadle is locked
  500.         GetFlavorData(theDrag, theItem, theDragFlavor, &(**thePrivateData).myData[0], &dataSize, 0L);
  501.  
  502.         HUnlock( (Handle)thePrivateData ) ;
  503.  
  504.         // package this puppy up and send it to ourselves
  505.         SendDragRecv( thePrivateData ) ;
  506.         
  507.         // and dispose of the data
  508.         DisposeHandle((Handle)thePrivateData ) ;
  509.  
  510.         if (attributes & dragHasLeftSenderWindow) {
  511.             HideDragHilite(theDrag);
  512.         }
  513.     }
  514.     
  515.     return(noErr);
  516.     
  517. bail:
  518.     return(memFullErr);
  519. }
  520.  
  521.  
  522. //-----------------------------------------------------------------------
  523. //    MyTrackingHandler
  524. //
  525. //    This is the drag tracking handler for windows in the Dragging application.
  526.  
  527. pascal OSErr MyTrackingHandler(short theMessage, WindowPtr theWindow,
  528.                                void *handlerRefCon, DragReference theDrag);
  529.  
  530. pascal OSErr MyTrackingHandler(short theMessage, WindowPtr theWindow,
  531.                                void *handlerRefCon, DragReference theDrag)
  532.  
  533. {
  534.  
  535.     RgnHandle    tempRgn;
  536.     Boolean        mouseInContentFlag;
  537.     OSErr        retCode;
  538.     
  539.     retCode = noErr;
  540.     
  541.     switch (theMessage) {
  542.     
  543.         case dragTrackingEnterHandler:
  544.             
  545.             // determine if the items are acceptable and store
  546.             // that flag in the globals, plus reset the
  547.             // hilighted global flag
  548.             
  549.             pDragHandlerGlobals.acceptableDragFlag = 
  550.                 DragItemsAreAcceptable(theDrag);
  551.             pDragHandlerGlobals.windowIsHilightedFlag = false;
  552.             
  553.             // let the drag manager know if we can't accept this drag
  554.             if (!pDragHandlerGlobals.acceptableDragFlag)
  555.                 retCode = dragNotAcceptedErr;
  556.             break;
  557.             
  558.         case dragTrackingEnterWindow: 
  559.         case dragTrackingInWindow:
  560.         case dragTrackingLeaveWindow:
  561.             
  562.             // highlighting of the window during a drag is done
  563.             // here.  Do it only if we can accept these items
  564.             // and we're not in the source window...
  565.             
  566.             if (pDragHandlerGlobals.acceptableDragFlag &&
  567.                 DragIsNotInSourceWindow(theDrag)) {
  568.                 
  569.                 // unless the mouse is leaving the visible area of the
  570.                 // window, check if it's in the window's content region
  571.                 
  572.                 if (theMessage == dragTrackingLeaveWindow)
  573.                     mouseInContentFlag = false;
  574.  
  575.                 else
  576.                     mouseInContentFlag = MouseIsInContentRgn(theDrag, theWindow);
  577.                 
  578.                 // if the mouse is in the content area and the window
  579.                 // is not yet hilighted, then do the hilighting
  580.                 
  581.                 if (mouseInContentFlag &&
  582.                     !pDragHandlerGlobals.windowIsHilightedFlag) {
  583.                     
  584.                     // set the proper clip
  585.                     ClipRect(&theWindow->portRect);
  586.                     
  587.                     // make a region bordering the window content
  588.                     tempRgn = NewRgn();
  589.                     RectRgn(tempRgn, &theWindow->portRect);
  590.                     
  591.                     // draw the hilight
  592.                     if (ShowDragHilite(theDrag, tempRgn, true) == noErr) {
  593.                         // remember that hilighting is now on
  594.                         pDragHandlerGlobals.windowIsHilightedFlag = true;
  595.                     }                    
  596.                     
  597.                     // free up the region
  598.                     DisposeRgn(tempRgn);
  599.                 }
  600.                 
  601.                 // else if the mouse is not in the content region
  602.                 // and the window is hilighted, erase the hilight
  603.                 
  604.                 else if (!mouseInContentFlag &&
  605.                     pDragHandlerGlobals.windowIsHilightedFlag) {
  606.                     
  607.                     // set the proper clip
  608.                     ClipRect(&theWindow->portRect);
  609.                     
  610.                     // erase the hilight and restore the port
  611.                     if (HideDragHilite(theDrag) == noErr)
  612.                     
  613.                         // remember that hilighting is now off
  614.                         pDragHandlerGlobals.windowIsHilightedFlag = false;
  615.                 }
  616.             }
  617.             break;
  618.  
  619.         // do nothing for the leaveHandler message
  620.         case dragTrackingLeaveHandler:
  621.             break;
  622.         
  623.         // let the drag manager know if we didn't recognize the message
  624.         default:
  625.             retCode = paramErr;
  626.     }
  627.     
  628.     return retCode;
  629. }
  630.  
  631.  
  632. //
  633. //    DropLocationIsFinderTrash
  634. //
  635. //    Returns true if the given dropLocation AEDesc is a descriptor of the Finder's Trash.
  636. //
  637.  
  638. static Boolean DropLocationIsFinderTrash(AEDesc *dropLocation)
  639.  
  640. {    OSErr            result;
  641.     AEDesc            dropSpec;
  642.     FSSpec            *theSpec;
  643.     CInfoPBRec        thePB;
  644.     short            trashVRefNum;
  645.     long            trashDirID;
  646.  
  647.     //
  648.     //    Coerce the dropLocation descriptor to an FSSpec. If there's no dropLocation or
  649.     //    it can't be coerced into an FSSpec, then it couldn't have been the Trash.
  650.     //
  651.  
  652.     if ((dropLocation->descriptorType != typeNull) &&
  653.         (AECoerceDesc(dropLocation, typeFSS, &dropSpec) == noErr)) {
  654.  
  655.         HLock(dropSpec.dataHandle);
  656.         theSpec = (FSSpec *) *dropSpec.dataHandle;
  657.  
  658.         //
  659.         //    Get the directory ID of the given dropLocation object.
  660.         //
  661.  
  662.         thePB.dirInfo.ioCompletion = 0L;
  663.         thePB.dirInfo.ioNamePtr = (StringPtr) &theSpec->name;
  664.         thePB.dirInfo.ioVRefNum = theSpec->vRefNum;
  665.         thePB.dirInfo.ioFDirIndex = 0;
  666.         thePB.dirInfo.ioDrDirID = theSpec->parID;
  667.  
  668.         result = PBGetCatInfo(&thePB, false);
  669.  
  670.         HUnlock(dropSpec.dataHandle);
  671.         AEDisposeDesc(&dropSpec);
  672.  
  673.         if (result != noErr)
  674.             return(false);
  675.  
  676.         //
  677.         //    If the result is not a directory, it must not be the Trash.
  678.         //
  679.  
  680.         if (!(thePB.dirInfo.ioFlAttrib & (1 << 4)))
  681.             return(false);
  682.  
  683.         //
  684.         //    Get information about the Trash folder.
  685.         //
  686.  
  687.         FindFolder(theSpec->vRefNum, kTrashFolderType, kCreateFolder, &trashVRefNum, &trashDirID);
  688.  
  689.         //
  690.         //    If the directory ID of the dropLocation object is the same as the directory ID
  691.         //    returned by FindFolder, then the drop must have occurred into the Trash.
  692.         //
  693.  
  694.         if (thePB.dirInfo.ioDrDirID == trashDirID)
  695.             return(true);
  696.     }
  697.  
  698.     return(false);
  699. }
  700.  
  701.  
  702. //
  703. //    DoDragObjects
  704. //
  705. //    Drag the selected text in the given document.
  706. //
  707.  
  708. short DoDragObjects(DocumentPtr theDocument, EventRecord *theEvent, RgnHandle hiliteRgn)
  709. {
  710.     short                result;
  711.     RgnHandle            dragRegion, tempRgn;
  712.     Point                theLoc;
  713.     DragReference        theDrag;
  714.     StScrpHandle        theStyl;
  715.     AEDesc                dropLocation;
  716.     DragAttributes        attributes;
  717.     short                mouseDownModifiers, mouseUpModifiers, copyText;
  718.     unsigned long        validSize;
  719.  
  720.     if( theDocument->documentGroup ) {
  721.  
  722.         Handle                theData;
  723.         TQ3StorageObject        storage;
  724.         TQ3FileObject        fd;
  725.         TQ3GroupPosition        position;
  726.         TQ3TransformObject     xform;
  727.         
  728.         DragSendDataUPP        mySendDataProcUPP ;
  729.         
  730.         //Q3Object_Dispose(pickObject);
  731.  
  732.         CopyRgn(hiliteRgn, dragRegion = NewRgn());
  733.         SetPt(&theLoc, 0, 0);
  734.         LocalToGlobal(&theLoc);
  735.         OffsetRgn(dragRegion, theLoc.h, theLoc.v);
  736.     
  737.         //
  738.         //    Wait for the mouse to move to the mouse button to be released. If the mouse button was
  739.         //    released before the mouse moves, return false. Returing false from DoDragObjects means that
  740.         //    a drag operation did not occur.
  741.         //
  742.     
  743.         if (! WaitMouseMoved(theEvent->where)) {
  744.             return(false);
  745.         }
  746.     
  747.         // create a new reference for a track to pass to track drag
  748.         NewDrag(&theDrag);
  749.     
  750.         //    We promise '3DMF' and 'PICT'.  If a receiver requests either, the Drag Manager
  751.         //    will call our MySendDataProc to provide the data at drop time. The MySendDataProc
  752.         //    is specified by calling SetDragSendProc.
  753.         AddDragItemFlavor(theDrag, 1, '3DMF', nil, 0L, 0L);
  754. //        AddDragItemFlavor(theDrag, 1, 'PICT', nil, 0L, 0L);
  755.         
  756.         mySendDataProcUPP = NewDragSendDataProc(MySendDataProc) ;
  757.         SetDragSendProc(theDrag, mySendDataProcUPP, (void *) theDocument);
  758.     
  759.         //    Set the item's bounding rectangle in global coordinates.
  760.         SetDragItemBounds(theDrag, 1, &(**dragRegion).rgnBBox);
  761.     
  762.         //    Prepare the drag region.
  763.         tempRgn = NewRgn();
  764.         CopyRgn(dragRegion, tempRgn);
  765.         InsetRgn(tempRgn, 1, 1);
  766.         DiffRgn(dragRegion, tempRgn, dragRegion);
  767.         DisposeRgn(tempRgn);
  768.     
  769.         // on PPC the drawing proc leaves artifacts on the display when 
  770.         // highlighting and upon removal of highlighting for a window, so
  771.         // although I may prefer the drawing that my custom proc does, I
  772.         // just use the default.  This may be a bug in the drag manager
  773.         // or it may be us, but right now we'll just a void doing this and fix later
  774. //            SetDragDrawingProc(theDrag,NewDragDrawingProc(MyDrawingProc), 0L);
  775.     
  776.         //    Drag the stuff. TrackDrag will return userCanceledErr if the drop zoomed-back
  777.         //    for any reason.
  778.         result = TrackDrag(theDrag, theEvent, dragRegion);
  779.         
  780.         // get rid of the UPP
  781.         DisposeRoutineDescriptor( mySendDataProcUPP ) ;
  782.     
  783.         if (result != noErr && result != userCanceledErr) {
  784.             return(true);
  785.         }
  786.     
  787.         //    Check to see if the drop occurred in the Finder's Trash. If the drop occurred
  788.         //    in the Finder's Trash and a copy operation wasn't specified, delete the
  789.         //    source selection. Note that we can continute to get the attributes, drop location
  790.         //    modifiers, etc. of the drag until we dispose of it using DisposeDrag.
  791.         GetDragAttributes(theDrag, &attributes);
  792.         if (!(attributes & dragInsideSenderApplication)) {
  793.     
  794.             GetDropLocation(theDrag, &dropLocation);
  795.     
  796.             GetDragModifiers(theDrag, 0L, &mouseDownModifiers, &mouseUpModifiers);
  797.             copyText = (mouseDownModifiers | mouseUpModifiers) & optionKey;
  798.     
  799.             if ((!copyText) && (DropLocationIsFinderTrash(&dropLocation))) {
  800.                 theDocument->dirty = true;
  801.                 Q3Object_Dispose(theDocument->documentGroup);
  802.                 theDocument->documentGroup = nil;
  803.             }
  804.     
  805.             AEDisposeDesc(&dropLocation);
  806.         }
  807.  
  808.         //    Dispose of the drag.
  809.         DisposeDrag(theDrag);
  810.         DisposeRgn(dragRegion);
  811.         return(true);
  812.     }
  813. bail:
  814.     return(false);
  815. }
  816.  
  817.  
  818.  
  819.  
  820.